package picasa;

import java.awt.*;

public class BrightnessAlg extends Frame implements ImageInterface{

  //This method is required by ImageInterface.
  public int[][][] processImg(
                            int[][][] threeDPix,
                            int imgRows,
                            int imgCols, double contrast, double brightness){

    //Make a working copy of the 3D array to
    // avoid making permanent changes to the
    // original image data.
    int[][][] output3D = threeDPix;

    //Get, save, display, and remove the mean.
    int mean = getMean(output3D,imgRows,imgCols);
    System.out.println("Original mean: " + mean);
    removeMean(output3D,imgRows,imgCols,mean);

    //Get and display the rms value.  The rms
    // value is for user information only.  It
    // is not actually used by the program.
    int rms = getRms(output3D,imgRows,imgCols);
    System.out.println("Original rms: " + rms);

    //Scale each color value by the contrast
    // multiplier.  This will either expand or
    // compress the distribution.
    scale(output3D,imgRows,imgCols,contrast);
    System.out.println("New rms"
             + getRms(output3D,imgRows,imgCols));

    //Restore the mean to a non-zero value by
    // adding the same value to each color value.
    // The value added is the product of the
    // new mean and the brightness multiplier.
    shiftMean(output3D,imgRows,imgCols,
                         (int)(brightness*mean));
    System.out.println("New mean : "
            + getMean(output3D,imgRows,imgCols));

    //Clip all color values at 0 and 255 to make
    // certain that no color value is out of the
    // range of an unsigned byte.
    clip(output3D,imgRows,imgCols);
    System.out.println();

    //Return the modified 3D array of pixel data.
    return output3D;

  }//end processImg
  //-------------------------------------------//

  //Method to calculate and return the mean
  // of all the color values
  int getMean(int[][][] data3D,int imgRows,
                                    int imgCols){

    int pixelCntr = 0;
    long accum = 0;
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        accum += data3D[row][col][1];
        accum += data3D[row][col][2];
        accum += data3D[row][col][3];
        pixelCntr += 3;
      }//end inner for loop
    }//end outer for loop

    return (int)(accum/pixelCntr);

  }//end getMean
  //-------------------------------------------//

  //Method to remove the mean causing the new
  // mean value to be 0
  void removeMean(int[][][] data3D,int imgRows,
                           int imgCols,int mean){
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        data3D[row][col][1] -= mean;
        data3D[row][col][2] -= mean;
        data3D[row][col][3] -= mean;
      }//end inner for loop
    }//end outer for loop
  }//end removeMean
  //-------------------------------------------//

  //Method to calculate the root mean square
  // value of all the color values.
  int getRms(int[][][] data3D,int imgRows,
                                    int imgCols){
    int pixelCntr = 0;
    long accum = 0;
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        accum += data3D[row][col][1] *
                             data3D[row][col][1];
        accum += data3D[row][col][2] *
                             data3D[row][col][2];
        accum += data3D[row][col][3] *
                             data3D[row][col][3];
        pixelCntr += 3;
      }//end inner for loop
    }//end outer for loop
    int meanSquare = (int)(accum/pixelCntr);
    int rms = (int)(Math.sqrt(meanSquare));
    return rms;
  }//end getRms
  //-------------------------------------------//

  //Method to scale the data and expand or
  // compress the distribution
  void scale(int[][][] data3D,int imgRows,
                       int imgCols,double scale){
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        data3D[row][col][1] *= scale;
        data3D[row][col][2] *= scale;
        data3D[row][col][3] *= scale;
      }//end inner for loop
    }//end outer for loop
  }//end scale
  //-------------------------------------------//

  //Method to shift the mean to a new value.
  void shiftMean(int[][][] data3D,int imgRows,
                        int imgCols,int newMean){
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        data3D[row][col][1] += newMean;
        data3D[row][col][2] += newMean;
        data3D[row][col][3] += newMean;
      }//end inner for loop
    }//end outer for loop
  }//end shiftMean
  //-------------------------------------------//

  //Method to clip the color data at 0 and 255
  void clip(int[][][] data3D,int imgRows,
                                    int imgCols){
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        if(data3D[row][col][1] < 0)
          data3D[row][col][1] = 0;
        if(data3D[row][col][1] > 255)
          data3D[row][col][1] = 255;

        if(data3D[row][col][2] < 0)
          data3D[row][col][2] = 0;
        if(data3D[row][col][2] > 255)
          data3D[row][col][2] = 255;

        if(data3D[row][col][3] < 0)
          data3D[row][col][3] = 0;
        if(data3D[row][col][3] > 255)
          data3D[row][col][3] = 255;

      }//end inner for loop
    }//end outer for loop
  }//end clip
  //-------------------------------------------//

}//end class BrightnessAlg

